#!/usr/bin/env python
# -*- coding: utf-8 -*-

#  code copy from https://github.com/shuizhengqi1/DingCrypto/blob/master/DingCrypto.py

# 依赖Crypto类库
# pip install pycryptodome #  python3 安装Crypto
# API说明
# getEncryptedMap 生成回调处理成功后success加密后返回给钉钉的json数据
# decrypt  用于从钉钉接收到回调请求后
import time
import json
import uuid
from rest_framework.views import APIView
from xpack.serializers.platform_serializer import ConfigSerializer
from rest_framework.request import Request
from rest_framework.permissions import AllowAny
from rest_framework.decorators import action, permission_classes
from django.http import HttpResponse
import requests
from django.core.cache import caches
from dataset.serializers.file_serializers import FileSerializer
from application.serializers.chat_serializers import ChatSerializers
from django.db.models import Q, QuerySet
from application.models import Application
from application.serializers.chat_message_serializers import ChatInfo, ChatMessageSerializer
from django.core.cache import caches
from dataset.serializers.file_serializers import FileSerializer
from common.util.common import bytes_to_uploaded_file
from common.util.aes_util import DingtalkAesHandler
import threading

cache = caches['default_file']
chat_cache = caches['chat_cache']

class DingtalkMessage(APIView):
    def get_access_token(self, appid, appsecret):
        access_token_cache_key = appid + '_access_token'
        access_token = cache.get(access_token_cache_key)
        if access_token is None:
            url = f"https://oapi.dingtalk.com/gettoken?appkey={appid}&appsecret={appsecret}"
            response = requests.get(url)
            data = response.json()
            if data.get('errcode', None) != 0:
                print('get_access_token', data.get('errmsg'))
                return None
            access_token = data.get('access_token', None)
            if access_token is not None:
                cache.set(access_token_cache_key, access_token, 7200)
        
        return access_token
    def get_media_info(self, media_id,robot_id, wx_config):
        access_token = self.get_access_token(wx_config['client_id'], wx_config['client_secret'])
        if access_token is None:
            return None
        url = f"https://api.dingtalk.com/v1.0/robot/messageFiles/download"
        headers = {'x-acs-dingtalk-access-token': access_token}
        post = {
            "downloadCode": media_id,
            "robotCode": robot_id
        }
        response = requests.post(url, json=post, headers=headers)
        # 确保请求成功
        if response.status_code == 200:
            data = json.loads(response.content)
            downloadResponse = requests.get(data['downloadUrl'])
            if downloadResponse.status_code != 200:
                return None
            file_bytes = downloadResponse.content
            file_name = time.strftime("%Y%m%d%H%M%S", time.localtime()) + '.png'
            file = bytes_to_uploaded_file(file_bytes, file_name)
            return file
    def send_custom_message(self, content, req,  wx_config):
        access_token = self.get_access_token(wx_config['client_id'], wx_config['client_secret'])
        if access_token is None:
            return None
        url = f"https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend"
        headers = {'x-acs-dingtalk-access-token': access_token}
        reply = {
            "content": content,
        }
        msg = {
            "msgParam": json.dumps(reply),
            "msgKey": 'sampleText',
            "userIds": req['receive_ids'],
            "robotCode": req['sender_id']
        }
        response = requests.post(url, json=msg,headers=headers)
        return response.json()
    def chat(self,messages,req):
        # {question} 为用户问题 {trigger_message} 继续
        # chat_record_id_cache_key = req['chat_id'] + '_chat_record_id'
        data = {
            'chat_id': req['chat_id'], 
            'message': messages['message'],
            're_chat': False,
            'stream': False,
            'application_id': req['application_id'],
            'client_id': req['client_id'],
            'form_data': {},
            'image_list': messages['image_list'],
            'document_list': [],
            'audio_list': [],
            'client_type': 'USER',
            'node_id': None,
            'runtime_node_id': None,
            'node_data': {},
            'chat_record_id': None,
            'child_node': {}
        }
        # chat_record_id = None
        chat_record_list = []
        response = ChatMessageSerializer(data = data).chat()
        res_list = []
        if response is None:
            chat_record_list = [{"content": "抱歉，没有查找到相关内容，请重新描述您的问题或提供更多信息。"}]
            chat_cache.set(messages['id'], chat_record_list)
            return messages['id']
        if response.status_code == 200:
            if response.content is not None:
                chat_record = json.loads(response.content)
                if chat_record['code'] == 200:
                    chat_record_list.append(chat_record['data'])
                    # chat_record_id = chat_record_list[0]['id']
                    # cache.set(chat_record_id_cache_key,chat_record_id)
            elif response.streaming_content is not None:
                res_list = list(response.streaming_content)
                if len(res_list) > 0:
                    for chunk in res_list:
                        if chunk[0:5] == b'data:':
                            jsons = json.loads(chunk[5:].decode('utf-8'))
                            if type(jsons['content']) != str:
                                continue
                            chat_record_list.append(jsons)
                    # chat_record_id = chat_record_list[0]['chat_record_id']
                    # cache.set(chat_record_id_cache_key,chat_record_id)
        # if chat_record_id is not None:
        chat_cache.set(messages['id'], chat_record_list)
        print('生成结果', chat_record_list)
        return messages['id']
    @action(methods=['POST'], detail=False)
    @permission_classes((AllowAny,))
    def post(self, request: Request, application_id: str):
        file = open("dingtalk_get.txt", "a")
        file.write(json.dumps(request.GET))
        file.close()
        file = open("dingtalk_body.txt", "a")
        file.write(request.body.decode("utf-8"))
        file.close()
        application = QuerySet(Application).filter(id=application_id).first()
        if application is None:
            return HttpResponse("应用不存在")
        user_id = str(application.user_id)
        where = {
            "app_id": application_id,
            "platform": "dingtalk",
        }
        wx_config = ConfigSerializer.Query(data = where).info()
        if wx_config is None:
            return HttpResponse("钉钉配置不存在")
        req = {
            "signature": request.GET.get('signature', ''),
            "timestamp": request.GET.get('timestamp', str(time.time())),
            "nonce": request.GET.get('nonce', ''),
            "openid": request.GET.get('openid', ''),
            "encrypt": request.GET.get('encrypt', ''),
            "encrypt_type": request.GET.get("encrypt_type", "raw"),
            "msg_signature": request.GET.get("msg_signature", ""),
            "application_id": application_id,
            "content": "",
            "wechat_access_token": "",
            "receive_ids": [],
            "sender_id": ""
        }
        token = "pyaT0v8pwsolDkGWyvnzwuVZZG7FDEHKthv1pGTYqJHmSL"
        aes_key = "imsNcKegkEb8a7HpXO18zKoSdjTMLQNq7kvn7tNYLTn"
        agent_id = "3548506305"
        app_key = wx_config.get("client_id") #原appkey
        app_secret = wx_config.get("client_secret") #原appsecret
        dingCrypto = DingtalkAesHandler(token, aes_key, app_key)
        json_dict = json.loads(request.body.decode("utf-8"))
        if 'encrypt' in json_dict:
            echo_str = dingCrypto.getDecryptMsg(req['msg_signature'],req['timestamp'],req['nonce'],json_dict['encrypt'])
            msg = json.loads(echo_str)
            if msg['EventType'] == "check_url":
                res = dingCrypto.getEncryptedMap("success")
                return HttpResponse(json.dumps(res))
        elif 'msgtype' in json_dict:
            req['openid'] = json_dict['senderStaffId']
            if req['openid'] == "":
                return HttpResponse("openid为空")
            chat_id_cache_key = application_id + '_chatid_' + req['openid']
            client_id_cache_key = application_id + '_client_' + req['openid']
            client_id = cache.get(client_id_cache_key)
            if client_id is None:
                client_id = str(uuid.uuid1())
                cache.set(client_id_cache_key, client_id)
            chat_id = cache.get(chat_id_cache_key)
            if chat_id is None:
                chat_id = ChatSerializers.OpenChat(data={'user_id':user_id, 'application_id': application_id}).open()
                cache.set(chat_id_cache_key, chat_id)
            req['chat_id'] = chat_id
            req['client_id'] = client_id
            req['sender_id'] = json_dict['robotCode']
            req['receive_ids'] = [json_dict['senderStaffId']]
            messages = {
                'id': str(uuid.uuid1()),
                'type': json_dict['msgtype'],
                'message': "随便回复点什么",
                'image_list': [],
                'audio_list': [],
            }
            if messages['type'] == 'text':
                messages['message'] = json_dict['text']['content']
            elif messages['type'] == 'picture':
                messages['message'] = "请用中文解析图片内容"
                file = self.get_media_info(json_dict['content']['downloadCode'],json_dict['robotCode'],wx_config)
                if file is not None:
                    meta = {
                        'debug': False,
                        'chat_id': chat_id,
                        'application_id': application_id,
                    }
                    file_url = FileSerializer(data={'file': file, 'meta': meta}).upload()
                    messages['image_list'] = [{'file_id': file_url.split('/')[-1], 'url': file_url}]
            elif messages['type'] == 'audio':
                messages['message'] = "请用中文解析语音内容"
                if json_dict['content']['recognition'] is not None and json_dict['content']['recognition'] != "":
                    messages['message'] = json_dict['content']['recognition']
                file = self.get_media_info(json_dict['content']['downloadCode'],json_dict['robotCode'],wx_config)
                if file is not None:
                    meta = {
                        'debug': False,
                        'chat_id': chat_id,
                        'application_id': application_id,
                    }
                    file_url = FileSerializer(data={'file': file, 'meta': meta}).upload()
                    messages['audio_list'] = [{'file_id': file_url.split('/')[-1], 'url': file_url}]
            threading.Thread(target=self.chat, args=(messages, req)).start()
            threading.Thread(target=self.async_reply, args=(messages,req, wx_config)).start()
        return HttpResponse("success")
    def async_reply(self, messages, req, wx_config):
        i = 0
        while True:
            time.sleep(3)
            print("聊天记录ID", messages['id'])
            chat_record_list = chat_cache.get(messages['id'])
            print("本次消息", chat_record_list)
            
            if i >= 10:
                print("抱歉，没有查找到相关内容，请重新描述您的问题或提供更多信息。")
                return False
            i+=1
            if chat_record_list is not None and len(chat_record_list) > 0:
                content = ""
                for chat_record in chat_record_list:
                    content += chat_record['content']
                n = 600
                segments = [content[i:i + n] for i in range(0, len(content), n)]
                for segment in segments:
                    print(segment)
                    self.send_custom_message(segment, req, wx_config)
                
                return True